namespace Crux.Core.LangChain.Databases.Sqlite;

/// <summary>
/// 
/// </summary>
public static class Utils
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="vector1"></param>
    /// <param name="vector2"></param>
    /// <returns></returns>
    public static float ComputeEuclideanDistance(float[] vector1, float[] vector2)
    {
        vector1 = vector1 ?? throw new ArgumentNullException(nameof(vector1));
        vector2 = vector2 ?? throw new ArgumentNullException(nameof(vector2));

        double sum = 0.0;
        for (int i = 0; i < vector1.Length; i++)
        {
            sum += Math.Pow(vector1[i] - vector2[i], 2);
        }

        return (float)Math.Sqrt(sum);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="vector1"></param>
    /// <param name="vector2"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    public static float ComputeManhattanDistance(float[] vector1, float[] vector2)
    {
        vector1 = vector1 ?? throw new ArgumentNullException(nameof(vector1));
        vector2 = vector2 ?? throw new ArgumentNullException(nameof(vector2));

        double sum = 0.0;
        for (int i = 0; i < vector1.Length; i++)
        {
            sum += Math.Abs(vector1[i] - vector2[i]);
        }

        return (float)sum;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="vector1"></param>
    /// <param name="vector2"></param>
    /// <returns></returns>
    public static float CosineSimilarity(float[] vector1, float[] vector2)
    {
        double dotProduct = 0;
        double normA = 0;
        double normB = 0;

        for (int i = 0; i < vector1.Length; i++)
        {
            dotProduct += vector1[i] * vector2[i];
            normA += Math.Pow(vector1[i], 2);
            normB += Math.Pow(vector2[i], 2);
        }
        return (float)(dotProduct / (Math.Sqrt(normA) * Math.Sqrt(normB)));
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="vector1"></param>
    /// <param name="vector2"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static float DotProductSimilarity(float[] vector1, float[] vector2)
    {
        if (vector1.Length != vector2.Length)
        {
            throw new ArgumentException("Vectors must be of the same dimension.");
        }

        double dotProduct = 0;

        for (int i = 0; i < vector1.Length; i++)
        {
            dotProduct += vector1[i] * vector2[i];
        }

        return (float)dotProduct;
    }
}